package timing.ukulele.flow.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import timing.ukulele.common.ResponseResult;
import timing.ukulele.flow.dictionary.FlowStatusEnum;
import timing.ukulele.flow.extention.CustomBpmnJsonConverter;
import timing.ukulele.flow.persistent.Flow;
import timing.ukulele.flow.service.FlowService;
import io.swagger.annotations.*;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipInputStream;

/**
 * 部署流程、删除流程
 */

@RestController
@Api(tags = "部署流程、删除流程")
public class DeployController {

    private final RepositoryService repositoryService;
    private final FlowService flowService;

    public DeployController(RepositoryService repositoryService, FlowService flowService) {
        this.repositoryService = repositoryService;
        this.flowService = flowService;
    }

    @PostMapping(path = "deploy/model/{modelId}/{bpmnName}")
    @ApiOperation(value = "根据modelId部署流程,deploymentId为model部署成功之后的id,deploymentName为部署之后的模型名称", notes = "根据modelId部署流程")
    public ResponseResult deployById(@ApiParam("流程名称") @PathVariable("bpmnName") String bpmnName,
                                     @ApiParam("modelId") @PathVariable("modelId") String modelId) {
        Deployment deployment;
        try {
            byte[] modelEditorSource = repositoryService.getModelEditorSource(modelId);
            Model model = repositoryService.getModel(modelId);
            if (model == null) {
                return ResponseResult.error("不存在该Model");
            }
            if (modelEditorSource == null) {
                return ResponseResult.error("Model中不存在数据资源");
            }
            ObjectNode modelNode = (ObjectNode) new ObjectMapper().readTree(modelEditorSource);
            CustomBpmnJsonConverter converter = new CustomBpmnJsonConverter();
            BpmnModel bpmnModel = converter.convertToBpmnModel(modelNode);// 转model
            DeploymentBuilder deploymentBuilder = repositoryService.createDeployment()
                    .name(bpmnName)
                    .enableDuplicateFiltering()
                    .addBpmnModel(bpmnName.concat(".bpmn20.xml"), bpmnModel);
            deployment = deploymentBuilder.tenantId(model.getTenantId()).key(model.getKey()).deploy();
        } catch (Exception e) {
            return ResponseResult.error("部署失败");
        }
        if (deployment != null) {
            //更新流程模型状态：已发布
            flowService.lambdaUpdate().set(Flow::getStatus, FlowStatusEnum.PUBLISHED).eq(Flow::getFlowKey, modelId).update();
            Map<String, String> result = new HashMap<>(4);
            result.put("deploymentId", deployment.getId());
            result.put("deploymentName", deployment.getName());
            return ResponseResult.success(result);
        }
        return ResponseResult.error("部署失败");
    }

    @PostMapping(path = "deleteProcess/{deploymentId}")
    @ApiOperation(value = "根据部署ID删除流程", notes = "根据部署ID删除流程")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "deploymentId", value = "部署ID", dataType = "String", paramType = "query", example = "")
    })
    public ResponseResult deleteProcess(@PathVariable("deploymentId") String deploymentId) {
        try {
            /**不带级联的删除：只能删除没有启动的流程，如果流程启动，就会抛出异常*/
            repositoryService.deleteDeployment(deploymentId);
//            /**级联删除：不管流程是否启动，都能可以删除（emmm大概是一锅端）*/
//            repositoryService.deleteDeployment(deploymentId, true);
            return ResponseResult.success("删除成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ResponseResult.error("删除失败");
    }

    @PostMapping(path = "deploy/{bpmnName}")
    @ApiOperation(value = "根据bpmnName部署流程", notes = "根据bpmnName部署流程")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "bpmnFile", value = "设计的流程图名称", dataType = "MultipartFile", paramType = "body")
    })
    public ResponseResult deploy(@ApiParam("流程名称") @PathVariable("bpmnName") String bpmnName,
                                 @RequestBody() MultipartFile bpmnFile) {

        //创建一个部署对象
        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment().name(bpmnName);
        Deployment deployment;
        try {
            deployment = deploymentBuilder.addInputStream(bpmnName, bpmnFile.getInputStream()).deploy();
        } catch (Exception e) {
            return ResponseResult.error("部署失败：" + e.getMessage());
        }

        if (deployment != null) {
            Map<String, String> result = new HashMap<>(4);
            result.put("deployID", deployment.getId());
            result.put("deployName", deployment.getName());
            return ResponseResult.success(result);
        }
        return ResponseResult.error("部署失败");
    }

    @PostMapping(path = "deployZIP/{zipName}")
    @ApiOperation(value = "根据ZIP压缩包部署流程", notes = "根据ZIP压缩包部署流程")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "bpmnFile", value = "设计的流程图名称", dataType = "MultipartFile", paramType = "body")
    })
    public ResponseResult deployZIP(@ApiParam("设计的流程图和图片的压缩包名称") @PathVariable("zipName") String zipName,
                                    @RequestBody() MultipartFile bpmnFile) {
        Deployment deployment;
        try {
            ZipInputStream zipInputStream = new ZipInputStream(bpmnFile.getInputStream());
            deployment = repositoryService.createDeployment()
                    .name(zipName)
                    //指定zip格式的文件完成部署
                    .addZipInputStream(zipInputStream)
                    .deploy();//完成部署
            zipInputStream.close();
        } catch (Exception e) {
            return ResponseResult.error("部署失败：" + e.getMessage());
        }
        if (deployment != null) {
            Map<String, String> result = new HashMap<>(4);
            result.put("deployID", deployment.getId());
            result.put("deployName", deployment.getName());
            return ResponseResult.success(result);
        }
        return ResponseResult.error("部署失败");
    }

    @PostMapping(path = "deleteProcess")
    @ApiOperation(value = "根据部署ID删除流程", notes = "根据部署ID删除流程")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "deploymentId", value = "部署ID", dataType = "String", paramType = "query", example = ""),
            @ApiImplicitParam(name = "cascade", value = "是否级联删除,true:级联删除：不管流程是否启动，都能可以删除;false:不带级联的删除：只能删除没有启动的流程，如果流程启动，就会抛出异常", dataType = "Boolean", paramType = "query", example = "false")
    })
    public ResponseResult deleteProcess(@RequestParam("deploymentId") String deploymentId, @RequestParam("") Boolean cascade) {
        try {
            repositoryService.deleteDeployment(deploymentId, cascade);
            return ResponseResult.success();
        } catch (Exception e) {
            return ResponseResult.error("删除失败:" + e.getMessage());
        }

    }
}
